#include "EpollServer.hpp"

EpollServer::EpollServer(func_t func, int port, const std::string& ip)
    : _func(func), _listenSock(-1), _epfd(-1)
    , _port(port), _ip(ip), _ptr_events(nullptr)
{
    // 1.获取监听套接字
    _listenSock = Sock::Socket();
    if(_listenSock < 0) exit(1);

    // 2.绑定端口号
    if(Sock::Bind(_listenSock, _ip, _port) < 0){
        exit(2);
    }

    // 3.设置监听状态
    if(Sock::Listen(_listenSock) < 0) {
        exit(3);
    }

    // 4.创建Socket模型
    _epfd = Epoll::EpollCreate();
    if(_epfd < 0) {
        exit(4);
    }

    // 5.将Listen套接字添加到epoll中去
    if(Epoll::EpollCtl(_epfd, EPOLL_CTL_ADD, _listenSock, EPOLLIN) < 0) {
        exit(5);
    }

    // 6.开辟就绪队列所需的空间
    _ptr_events = new epoll_event[g_maxevents];
    if(_ptr_events == nullptr) {
        logMessage(ERROR, "Malloc _ptr_events fail!\n");
        exit(6);
    }

    logMessage(NORMAL, "Epoll Server init success, _listenSock:%d, _epfd:%d\n", _listenSock, _epfd);
}

// 服务器启动运行函数
void EpollServer::Start()
{
    // 0.服务器进程为常驻进程，死循环运行
    while(true)
    {
        // 1. 等待一个或多个事件就绪
        int n = Epoll::EpollWait(_epfd, _ptr_events, g_maxevents, g_timeout);

        switch(n)
        {
        case 0:    // timeout，没有事件就绪
            logMessage(DEBUG, "Time out!\n");
            break;
        case -1:   // 等待发生错误
            logMessage(ERROR, "Epoll wait error, errno:%d, errMsg:%s\n", errno, strerror(errno));
            break;
        default:
            Handler(n);   // 3. 如果有时间就绪就进行处理
            break;
        }
    }
}

// 析构函数
EpollServer::~EpollServer()
{
    if(_listenSock >= 0) close(_listenSock);
    if(_epfd) close(_epfd);
    if(_ptr_events) delete[] _ptr_events;
}

// 就绪事件处理函数
void EpollServer::Handler(int n)
{
    // 1. 遍历_ptr_events，检测已经就绪的事件
    for(int i = 0; i < n; ++i)
    {
        // 如果读时间就绪
        if(_ptr_events[i].events & EPOLLIN)
        {
            // 2. 判读就绪的是listen套接字还是普通套接字，分类处理
            if(_ptr_events[i].data.fd == _listenSock) Accepter(_listenSock);
            else Reciever(_ptr_events[i].data.fd);
        }
    }
}

// 接收客户端连接函数
void EpollServer::Accepter(int listenSock)
{
    std::string cli_ip;
    uint16_t cli_port;   // 客户端ip和端口号

    // 1.获取客户端连接
    int sock = Sock::Accept(listenSock, cli_ip, cli_port);

    if(sock < 0)
    {
        logMessage(ERROR, "Accept fail, errno:%d, errMsg:%s\n", errno, strerror(errno));
        return;
    }
    logMessage(NORMAL, "Get a link success, cli_ip:%s, cli_port:%u, sock:%d\n", cli_ip.c_str(), cli_port, sock);

    // 2.将新的时间添加到epoll中去
    int ret = Epoll::EpollCtl(_epfd, EPOLL_CTL_ADD, sock, EPOLLIN);
    if(ret < 0)
    {
        logMessage(ERROR, "Add new event fail, sock:%d, errno:%d, strMsg:%s\n", sock, errno, strerror(errno));
    }
    logMessage(NORMAL, "Add new event success, sock:%d\n", sock);
}

// 读取数据函数
void EpollServer::Reciever(int sock)
{
    char buffer[SIZE];
    ssize_t n = recv(sock, buffer, (SIZE) - 1, 0);

    // 如果成功读取对端数据
    if(n > 0)
    {
        buffer[n] = '\0';
        logMessage(NORMAL, "Recieve mesasge from client success, Message# \n", buffer);

        _func(buffer);   // 处理数据
    }
    else if(n == 0)   // 对端关闭
    {
        logMessage(DEBUG, "Client close, sock:%d\n", sock);

        // 将对应的事件从epoll关注事件中移除
        int ret = Epoll::EpollCtl(_epfd, EPOLL_CTL_DEL, sock, EPOLLIN);

        if(ret < 0) {
            logMessage(ERROR, "Delete event fail, errno:%d, errMsg:%s\n", errno, strerror(errno));
        }
        else {
            logMessage(NORMAL, "Delete event success, sock:%d\n", sock);
        }

        close(sock);   // 关闭对应文件描述符
    }
    else  // 读取失败
    {
        logMessage(ERROR, "Recieve fail, errno:%d, errMsg:%s\n", errno, strerror(errno));
    }
}